package com.egao.common.module.counsel.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.egao.common.component.wechat.WeChatUtils;
import com.egao.common.core.exception.BusinessException;
import com.egao.common.core.web.JsonResult;
import com.egao.common.core.web.PageParam;
import com.egao.common.module.counsel.CounselConstants;
import com.egao.common.module.counsel.entity.Counsel;
import com.egao.common.module.counsel.entity.CounselStudent;
import com.egao.common.module.counsel.mapper.CounselMapper;
import com.egao.common.module.counsel.param.CounselParam;
import com.egao.common.module.counsel.result.CounselCalendarColumns;
import com.egao.common.module.counsel.service.CounselService;
import com.egao.common.module.counsel.service.CounselStudentService;
import com.egao.common.module.student.entity.Student;
import com.egao.common.module.student.service.StudentService;
import com.egao.common.module.system.entity.User;
import com.egao.common.module.system.service.EmailService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static com.egao.common.module.counsel.CounselConstants.COUNSEL_STATE_CANCEL;

/**
 * @author lym
 * @date 2022/1/24 17:11
 */
@Service
public class CounselServiceImpl extends ServiceImpl<CounselMapper, Counsel> implements CounselService {

    @Autowired
    private EmailService emailService;

    @Lazy
    @Autowired
    private CounselStudentService counselStudentService;

    @Autowired
    private StudentService studentService;

    @Override
    public boolean saveCycle(CounselParam counselParam) {
        for(int i = 0; i < counselParam.getWeek().size(); i++) {
            List<Date> weekDate = getWeekDateByRange(counselParam.getStartDate(), counselParam.getEndDate(), counselParam.getWeek().get(i));
            for (Date date : weekDate) {
                // 判断是否冲突
                LambdaQueryWrapper<Counsel> lqw = Wrappers.lambdaQuery(Counsel.class)
                        .eq(Counsel::getCounselDate, date)
                        .eq(Counsel::getState, CounselConstants.COUNSEL_STATE);
                List<Counsel> list = list(lqw);
                for(Counsel counsel : list) {
                    if (isTimeConflict(counsel, counselParam)) {
                        throw new BusinessException("存在冲突的时间段");
                    }
                }
                // 保存
                Counsel counsel = new Counsel();
                BeanUtils.copyProperties(counselParam, counsel);
                counsel.setSurplusCount(counselParam.getCount());
                counsel.setCounselDate(date);
                counsel.setState(CounselConstants.COUNSEL_STATE);
                if (!save(counsel)) {
                    throw new BusinessException("保存失败");
                }
            }

        }
        return true;
    }

    @Override
    public boolean updateCounsel(Counsel counsel) {
        CounselParam  param = new CounselParam();
        BeanUtils.copyProperties(counsel, param);
        // 判断是否冲突
        LambdaQueryWrapper<Counsel> lqw = Wrappers.lambdaQuery(Counsel.class)
                .eq(Counsel::getCounselDate, counsel.getCounselDate())
                .eq(Counsel::getState, CounselConstants.COUNSEL_STATE);
        List<Counsel> list = list(lqw);
        for(Counsel c : list) {
            if (isTimeConflict(c, param)) {
                throw new BusinessException("存在冲突的时间段");
            }
        }
        if (!updateById(counsel)) {
            return false;
        }
        return true;
    }


    @Override
    public List<CounselCalendarColumns> calendar(String dateStr, User user) {
        if (StrUtil.isBlank(dateStr)) {
            dateStr = DateUtil.now();
        }
        Date date = DateUtil.parse(dateStr);

        return getCounselList(date, user);
    }


    /**
     * 生成周一至周日的日历列头
     *
     * @param date 日期
     * @return List<CounselCalendarColumns>
     */
    private List<CounselCalendarColumns> getCounselList(Date date, User user) {
        List<CounselCalendarColumns> list = new ArrayList<>();
        String[] weekZh = new String[]{"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
        String[] weeksEn = new String[]{"mon", "tues", "wed", "thur", "fri", "satur", "sun"};

        DateTime beginDay = DateUtil.beginOfWeek(date);
        list.add(new CounselCalendarColumns(DateUtil.format(beginDay, "MM-dd"), weekZh[0], weeksEn[0], beginDay));

        for (int i = 1; i < 7; i++) {
            Date weekDay = DateUtil.offsetDay(beginDay, i);
            list.add(new CounselCalendarColumns(DateUtil.format(weekDay, "MM-dd"), weekZh[i], weeksEn[i], weekDay));
        }

        // 周预约数据
        List<Date> dateList = list.stream().map(CounselCalendarColumns::getDate).collect(Collectors.toList());
        PageParam<Counsel> pageParam = new PageParam<>();
        pageParam.put("state", CounselConstants.COUNSEL_STATE);
        pageParam.put("counselDate", dateList);
        pageParam.setSize(-1);
        List<Counsel> counselList = baseMapper.selectListRel(pageParam);

        // 如果学生已经登录，根据学生的预约记录去设置是否还能预约的值
        if (user != null) {
            if("2".equals(user.getUserType())) {
                Student student = studentService.getByUserId(user.getUserId());
                LambdaQueryWrapper<CounselStudent> qw = Wrappers.lambdaQuery(CounselStudent.class)
                        .eq(CounselStudent::getStudentId, student.getId());
                List<Integer> counselIdList = counselStudentService.list(qw).stream()
                        .map(CounselStudent::getCounselId).collect(Collectors.toList());
                counselList.forEach(item -> {
                    if (counselIdList.contains(item.getId())) {
                        item.setClickDisable(false);
                    }
                });
            }
        }

        // 如果人数满了也设置为false
        counselList.forEach(item -> {
            if (item.getSurplusCount() == 0) {
                item.setClickDisable(false);
            }
        });

        // 将咨询数据映射到对应的列
        list.forEach(item -> {
            List<Counsel> counsels  = counselList.stream()
                    .filter(counsel -> item.getDate().equals(counsel.getCounselDate())).collect(Collectors.toList());
            item.setCounselList(counsels);
        });

        return list;
    }

    @Override
    public JsonResult cancelCounsel(Counsel counsel, Student student) {
        if (System.currentTimeMillis() > counsel.getCounselDate().getTime()) {
            throw new BusinessException("预约时间已过不可取消");
        }

        counsel.setState(COUNSEL_STATE_CANCEL);
        counsel.setCancelDate(new Date());
        if (baseMapper.updateById(counsel) > 0) {
            if (student == null) {
                return JsonResult.ok();
            }

            try {
                // 发送邮件
                String content = "您在" + counsel.getCounselDate() + " " + counsel.getCounselTime() + "的预约咨询已被咨询师取消，取消原因：" + counsel.getCancel();
                emailService.sendTextEmail("预约咨询取消通知", content, new String[]{student.getEmail()});

                // 发送企业号消息
                WeChatUtils.push(new String[]{student.getXh()}, content);
            } catch (Exception e) {
                Console.error(e, "咨询师取消发送通知异常");
            }

            return JsonResult.ok();
        }

        return JsonResult.error();
    }

    /**
     * 从时间范围中获取指定星期列表
     * @param startDate
     * @param endDate
     * @param week
     * @return
     */
    private List<Date> getWeekDateByRange(Date startDate, Date endDate, Integer week) {
        List<Date> dateList = new ArrayList<>();
        while (!startDate.after(endDate)) {
            if (DateUtil.dayOfWeek(startDate) == week) {
                dateList.add(startDate);
            }
            startDate = DateUtil.offsetDay(startDate, 1);
        }
        return dateList;
    }


    /**
     * 判断时间是否冲突
     * @param counsel
     * @param counselParam
     * @return
     */
    private boolean isTimeConflict(Counsel counsel, CounselParam counselParam) {
        String ymd = DateUtil.format(counsel.getCounselDate(), "yyyy-MM-dd");
        List<String> times = StrUtil.split(counsel.getCounselTime(), '-');
        Date startDate = DateUtil.parse(ymd + " " + times.get(0) + ":01");
        Date endDate = DateUtil.parse(ymd + " " + times.get(1) + ":00");

        List<String> targetTimes = StrUtil.split(counselParam.getCounselTime(), '-');
        Date targetStartDate = DateUtil.parse(ymd + " " + targetTimes.get(0) + ":01");
        Date targetEndDate = DateUtil.parse(ymd + " " + targetTimes.get(1)+ ":00");

        // 判断是否有冲突
        return (targetStartDate.after(startDate) && targetStartDate.before(endDate))
                || (targetEndDate.after(startDate) && targetEndDate.before(endDate))
                || (targetStartDate.before(startDate) && targetEndDate.after(endDate))
                || (targetStartDate.equals(startDate) && targetEndDate.equals(endDate))
                || targetStartDate.equals(startDate)
                || targetEndDate.equals(endDate);

    }




}
